package program.TokenAndParser;

import java.util.ArrayList;

import Exceptions.ProgramError;

import program.Atom;
import program.SExprList;
import program.SExpression;
import program.Sequence;
import program.Command.Command;
import program.Command.Move;
import program.Command.PickupAndUse;
import program.Command.Shoot;
import program.Command.TurnClockWise;
import program.Command.TurnCounterClockWise;
import program.Condition.AtItem;
import program.Condition.CanHitRobot;
import program.Condition.Condition;
import program.Condition.EnergyAtLeast;
import program.Condition.True;
import program.Condition.Wall;
import program.Junction.And;
import program.Junction.NotCase;
import program.Junction.Or;
import program.Loop.If;
import program.Loop.While;
/**
 * 	A class representing the commandbuilder.
 * 
 * @author Jef Keijers/Bachelor of Science: Informatics
 * @version 1.0
 */
public class CommandBuilder {

	/**
	 * This method returns the translated (from SExpression to Command) command.
	 * @param 	command
	 * @throws	ProgramError
	 */ 
	public Command translateCommand(SExpression command) throws ProgramError { 
		ArrayList<SExpression> children = ((SExprList) command).getList();

		String commandToTranslate = ((Atom) children.get(0)).getCommand();

		if (commandToTranslate.equals("while")) {
			return new While(translateCondition(children.get(1)),
					translateCommand(children.get(2)));
		} else if (commandToTranslate.equals("if")) { 
			return new If(translateCondition(children.get(1)),
					translateCommand(children.get(2)),
					translateCommand(children.get(3)));
		} else if (commandToTranslate.equals("seq")) {
			ArrayList<Command> seq = new ArrayList<Command>();
			for (int i = 1; i < children.size(); i++) {
				seq.add(translateCommand(children.get(i)));
			}
			return new Sequence(seq);
		} else if (commandToTranslate.equals("move")) {
			return new Move();
		} else if (commandToTranslate.equals("shoot")) {
			return new Shoot();
		} else if (commandToTranslate.equals("pickup-and-use")) {
			return new PickupAndUse();
		} else if (commandToTranslate.equals("turn")) {
			if (isAtom(children.get(1), "clockwise"))
				return new TurnClockWise();
			else if (isAtom(children.get(1), "counterclockwise"))
				return new TurnCounterClockWise();
		}

		throw new ProgramError();
	}

	/**
	 * This method returns true if the given SExpression is an instance of Atom and the command
	 * that is represented by the give SExpression is the same as the given string.
	 * @param 	sexpr
	 * @param 	name
	 */
	public boolean isAtom(SExpression sexpr, String name) {
		return ((sexpr instanceof Atom) && ((Atom) sexpr).getCommand().equals(name));
	}

	/**
	 * This method returns the translated (from SExpression to Condition) condition.
	 * @param 	condition
	 * @throws 	ProgramError
	 */
	public Condition translateCondition(SExpression condition) throws ProgramError {
		ArrayList <SExpression> children = ((SExprList)condition).getList();
		
		String conditionToTranslate=((Atom)children.get(0)).getCommand();
		
		if (conditionToTranslate.equals("energy-at-least")) {
			return new EnergyAtLeast(((Atom)children.get(1)).getCommand());	  
		} else if (conditionToTranslate.equals("and")) {
			return new And(translateCondition(children.get(1)),translateCondition(children.get(2)));
		} else if (conditionToTranslate.equals("or")) {
			return new Or(translateCondition(children.get(1)),translateCondition(children.get(2)));
		} else if (conditionToTranslate.equals("not")) {
			return new NotCase(translateCondition(children.get(1)));
		} else if (conditionToTranslate.equals("true")) {
			return new True();  
		} else if (conditionToTranslate.equals("at-item")) {
			return new AtItem();	
		} else if (conditionToTranslate.equals("can-hit-robot")) {
			return new CanHitRobot();
		} else if (conditionToTranslate.equals("wall")) {
			return new Wall();
		}
		
		throw new ProgramError();
	}
}
